//
// Created by Crestimes on 24-5-10.
//

#include "Parser.h"

#include <iostream>
#include <utility>

Parser::Parser(std::vector<Token> tokens): tokens(std::move(tokens)) {}

TreeNode* Parser::getSyntaxTree() {
    TreeNode* root = program();
    return root;
}

TokenType Parser::nextTokenType() const {
    if (pos == tokens.size()) {
        return END;
    }
    return tokens[pos].type;
}

Token Parser::match(LeafNodeType t) {
    if (nextTokenType() == t) {
        return tokens[pos++];
    }
    throw QException();
    return {END, ""};
}

TreeNode* Parser::createNode(const Token& token) {
    auto* root = new TreeNode;
    root->leaf_str = token.str;
    return root;
}

TreeNode* Parser::program() {
    // program -> stmt-sequence
    auto* root = new TreeNode;
    root->branch_type = PROGRAM;
    root->children.push_back(stmt_sequence());
    return root;
}

TreeNode* Parser::stmt_sequence() {
    // stmt-sequence -> statement {';' statement }
    auto* root = new TreeNode;
    root->branch_type = STMT_SEQUENCE;
    root->children.push_back(statement());
    while (nextTokenType() == STMT_END) {
        match(STMT_END);
        root->children.push_back(statement());
    }
    return root;
}

TreeNode* Parser::statement() {
    // statement -> if-stmt | repeat-stmt | as-rg-stmt | read-stmt | write-stmt | while-stmt | for-stmt | exp-level4
    TreeNode* root = nullptr;
    if (nextTokenType() == IF) {
        root = if_stmt();
    }
    else if (nextTokenType() == REPEAT) {
        root = repeat_stmt();
    }
    else if (nextTokenType() == IDENTIFIER) {
        root = as_rg_stmt();
    }
    else if (nextTokenType() == READ) {
        root = read_stmt();
    }
    else if (nextTokenType() == WRITE) {
        root = write_stmt();
    }
    else if (nextTokenType() == WHILE) {
        root = while_stmt();
    }
    else if (nextTokenType() == FOR) {
        root = for_stmt();
    }
    else if(nextTokenType() == OP_SELF) {
        root = exp_level4();
    }
    else {
        throw QException();
    }
    return root;
}

TreeNode* Parser::as_rg_stmt() {
    // as-rg-stmt -> assign-stmt | regex-stmt
    auto* root = new TreeNode;
    root->branch_type = AS_RG_STMT;
    // 先存下来，因为还不知道是assign-stmt还是regex-stmt，create函数的branchType不确定
    auto identifier_temp = match(IDENTIFIER);
    if (nextTokenType() == EXP_EQ) {
        auto left = createNode(identifier_temp);
        auto assign_root = assign_stmt();
        assign_root->children.insert(assign_root->children.begin(), left);
        root->children.push_back(assign_root);
    }
    else if (nextTokenType() == REG_EQ) {
        auto left = createNode(identifier_temp);
        auto regex_root = regex_stmt();
        regex_root->children.insert(regex_root->children.begin(), left);
        root->children.push_back(regex_root);
    }
    else {
        throw QException();
    }
    return root;
}

TreeNode* Parser::regex_stmt() {
    // regex-stmt -> identifier '==' regex
    // identifier已经在上一级存了
    auto* root = createNode(match(REG_EQ));
    root->branch_type = REGEX_STMT;
    root->children.push_back(regex());
    return root;
}

TreeNode* Parser::if_stmt() {
    // if-stmt -> 'if' '(' exp ')' '[' stmt-sequence ']' [ 'else' '[' stmt-sequence ']' ]
    auto* root = new TreeNode;
    root->branch_type = IF_STMT;
    match(IF);
    match(LEFT_SMALL);
    root->children.push_back(exp());
    match(RIGHT_SMALL);
    match(LEFT_MID);
    root->children.push_back(stmt_sequence());
    match(RIGHT_MID);
    if (nextTokenType() == ELSE) {
        match(ELSE);
        match(LEFT_MID);
        root->children.push_back(stmt_sequence());
        match(RIGHT_MID);
    }
    return root;
}

TreeNode* Parser::repeat_stmt() {
    // repeat-stmt -> 'repeat' stmt-sequence 'until' exp
    auto* root = new TreeNode;
    root->branch_type = REPEAT_STMT;
    match(REPEAT);
    root->children.push_back(stmt_sequence());
    match(UNTIL);
    root->children.push_back(exp());
    return root;
}

TreeNode* Parser::assign_stmt() {
    // assign-stmt -> identifier ':=' exp
    // identifier返回后再存
    auto* root = createNode(match(EXP_EQ));
    root->branch_type = ASSIGN_STMT;
    root->children.push_back(exp());
    return root;
}

TreeNode* Parser::read_stmt() {
    // read-stmt -> 'read' identifier
    auto* root = new TreeNode;
    root->branch_type = READ_STMT;
    match(READ);
    root->children.push_back(createNode(match(IDENTIFIER)));
    return root;
}

TreeNode* Parser::write_stmt() {
    // write-stmt -> 'write' exp
    auto* root = new TreeNode;
    root->branch_type = WRITE_STMT;
    match(WRITE);
    root->children.push_back(exp());
    return root;
}

TreeNode* Parser::while_stmt() {
    // while-stmt -> 'while' '(' exp ')'
    auto* root = new TreeNode;
    root->branch_type = WHILE_STMT;
    match(WHILE);
    match(LEFT_SMALL);
    root->children.push_back(exp());
    match(RIGHT_SMALL);
    root->children.push_back(stmt_sequence());
    match(ENDWHILE);
    return root;
}

TreeNode* Parser::for_stmt() {
    // for-stmt -> 'for' '(' identifier assign-stmt ';' exp ';' exp-level4 ')' '[' stmt-sequence ']'
    auto* root = new TreeNode;
    root->branch_type = FOR_STMT;
    match(FOR);
    match(LEFT_SMALL);
    auto identifier_temp = createNode(match(IDENTIFIER));
    auto assign_root = assign_stmt();
    assign_root->children.push_back(assign_root->children[0]);
    assign_root->children[0] = identifier_temp;
    root->children.push_back(assign_root);
    match(STMT_END);
    root->children.push_back(exp());
    match(STMT_END);
    root->children.push_back(exp_level4());
    match(RIGHT_SMALL);
    match(LEFT_MID);
    root->children.push_back(stmt_sequence());
    match(RIGHT_MID);
    return root;
}

TreeNode* Parser::exp() {
    // exp -> exp-level0 { op-camp exp-level0 }
    auto* root = exp_level0();
    root->branch_type = EXP;
    while (nextTokenType() == OP_CAMP) {
        auto new_root = createNode(match(OP_CAMP));
        new_root->children.push_back(root);
        new_root->children.push_back(exp_level0());
        root = new_root;
    }
    return root;
}

TreeNode* Parser::exp_level0() {
    // exp-level0 -> exp-level1 { op-level0 exp-level1 }
    auto* root = exp_level1();
    root->branch_type = EXP_LEVEL0;
    while (nextTokenType() == OP_LEVEL0) {
        auto new_root = createNode(match(OP_LEVEL0));
        new_root->children.push_back(root);
        new_root->children.push_back(exp_level1());
        root = new_root;
    }
    return root;
}

TreeNode* Parser::exp_level1() {
    // exp-level1 -> exp-level2 { op-level1 exp-level2 }
    auto* root = exp_level2();
    root->branch_type = EXP_LEVEL1;
    while (nextTokenType() == OP_LEVEL1) {
        auto new_root = createNode(match(OP_LEVEL1));
        new_root->children.push_back(root);
        new_root->children.push_back(exp_level2());
        root = new_root;
    }
    return root;
}

TreeNode* Parser::exp_level2() {
    // exp-level2 -> exp-level3 { op-level2 exp-level3 }
    auto* root = exp_level3();
    root->branch_type = EXP_LEVEL2;
    while (nextTokenType() == OP_LEVEL2) {
        auto new_root = createNode(match(OP_LEVEL2));
        new_root->children.push_back(root);
        new_root->children.push_back(exp_level3());
        root = new_root;
    }
    return root;
}

TreeNode* Parser::exp_level3() {
    // exp-level3 -> '(' exp ')' | number | identifier | exp-level4
    TreeNode* root = nullptr;
    if (nextTokenType() == LEFT_SMALL) {
        match(LEFT_SMALL);
        root = exp();
        match(RIGHT_SMALL);
    }
    else if (nextTokenType() == NUMBER) {
        root = createNode(match(NUMBER));
    }
    else if (nextTokenType() == IDENTIFIER) {
        root = createNode(match(IDENTIFIER));
    }
    else if (nextTokenType() == OP_SELF) {
        root = exp_level4();
    }
    else {
        throw QException();
    }
    return root;
}

TreeNode* Parser::exp_level4() {
    // exp-level4 -> op-self identifier
    auto* root = createNode(match(OP_SELF));
    root->branch_type = EXP_LEVEL4;
    root->children.push_back(createNode(match(IDENTIFIER)));
    return root;
}

TreeNode* Parser::regex() {
    // regex -> '$' reg-level0 { '|' reg-level0 } '$'
    match(RE_LEFT_FLAG);
    auto* root = reg_level0();
    root->branch_type = REGEX;
    while (nextTokenType() == RE_OR) {
        auto new_root = createNode(match(RE_OR));
        new_root->children.push_back(root);
        new_root->children.push_back(reg_level0());
        root = new_root;
    }
    match(RE_RIGHT_FLAG);
    return root;
}

TreeNode* Parser::reg_level0() {
    // reg-level0 -> reg-level1 { '&' reg-level1 }
    auto* root = reg_level1();
    root->branch_type = REG_LEVEL0;
    while (nextTokenType() == RE_CONCAT) {
        auto new_root = createNode(match(RE_CONCAT));
        new_root->children.push_back(root);
        new_root->children.push_back(reg_level1());
        root = new_root;
    }
    return root;
}

TreeNode* Parser::reg_level1() {
    // reg-level1 -> reg-level2 [ '#' | '?' ]
    auto* root = reg_level2();
    root->branch_type = REG_LEVEL1;
    // 后面两个可选
    if (nextTokenType() == RE_ZERO_OR_MORE) {
        auto new_root = createNode(match(RE_ZERO_OR_MORE));
        new_root->children.push_back(root);
        root = new_root;
    }
    else if (nextTokenType() == RE_ZERO_OR_ONE) {
        auto new_root = createNode(match(RE_ZERO_OR_ONE));
        new_root->children.push_back(root);
        root = new_root;
    }
    return root;
}

TreeNode* Parser::reg_level2() {
    // reg-level2 -> re-char | '[' { re-char | reg-level3 } ']' | '.' | '(' reg-level1 ')'
    TreeNode* root = nullptr;
    // root->branch_type = REG_LEVEL2;
    if (nextTokenType() == RE_CHAR) {
        root = createNode(match(RE_CHAR));
    }
    else if (nextTokenType() == RE_LEFT_MID) {
        match(RE_LEFT_MID);
        while (true) {
            // 在词法分析的时候中括号里面的连续字符会加上&，而实际上应该不能有，在这里匹配并丢弃
            if (nextTokenType() == RE_CONCAT) match(RE_CONCAT);
            if (nextTokenType() == RE_CHAR) {
                if (root == nullptr) root = createNode(match(RE_CHAR));
                else root->children.push_back(createNode(match(RE_CHAR)));
            }
            else if (nextTokenType() == RE_CHAR_BEFORE_LINE) {
                if (root == nullptr) root = reg_level3();
                else root->children.push_back(reg_level3());
            }
            else break;
        }
        match(RE_RIGHT_MID);
    }
    else if (nextTokenType() == RE_ANY) {
        root = createNode(match(RE_ANY));
    }
    else if (nextTokenType() == RE_LEFT_SMALL) {
        match(RE_LEFT_SMALL);
        root = reg_level1();
        match(RE_RIGHT_SMALL);
    }
    else {
        throw QException();
    }
    return root;
}

TreeNode* Parser::reg_level3() {
    // reg-level3 -> re-range-char '-' re-char
    auto left = createNode(match(RE_CHAR_BEFORE_LINE));
    auto root = createNode(match(RE_LINE_IN_MID));
    auto right = createNode(match(RE_CHAR));
    root->branch_type = REG_LEVEL3;
    root->children.push_back(left);
    root->children.push_back(right);
    return root;
}
